package org.colafries.admin.querybuilder.customQuery;

import org.colafries.admin.entity.domain.DataModelConfig;
import org.colafries.admin.entity.vo.ColumnRspVO;
import org.colafries.admin.entity.vo.CustomQueryReqVO;
import org.colafries.admin.exceptions.ServiceException;
import org.colafries.admin.querybuilder.entity.CustomQueryParamContext;
import org.colafries.admin.querybuilder.utils.SqlSegmentBuilderUtil;
import org.colafries.common.enums.ColumnTypeEnum;
import org.colafries.admin.entity.domain.QueryParam;
import org.colafries.admin.querybuilder.entity.CustomQuerySqlBuildContext;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author colafries
 * @version v1.0
 * @ClassName FilterPartBuilder
 * @Description
 * @date Created in 2024/5/15
 **/
public class CustomQueryMeasureBuilder implements CustomQuerySqlSegmentBuilder {

    /**
     * @param customQueryParam
     * @return void
     * @author colafries
     * @Date 2024/5/16
     */
    @Override
    public void buildQueryParma(CustomQueryReqVO.CustomQueryParam customQueryParam, CustomQueryParamContext customQueryParamContext) {
        // 如果查询参数为空 or 模型配置为空 or 维度、度量都为空
        // 查询所有维度、度量
        if (Optional.ofNullable(customQueryParam)
                .map(queryParam -> CollectionUtils.isEmpty(queryParam.getDimensions())
                        && CollectionUtils.isEmpty(queryParam.getMeasures())
                )
                .orElse(true)) {
            // measure
            List<DataModelConfig> measureConfigs = customQueryParamContext.getDataModelListMap()
                    .get(ColumnTypeEnum.MEASURE.getValue());
            measureConfigs.forEach(config -> customQueryParamContext.getMeasures().add(createMeasure(config)));
        }

        //Measure
        Optional.ofNullable(customQueryParam)
                .map(CustomQueryReqVO.CustomQueryParam::getMeasures)
                .ifPresent(measures -> {
                    measures.forEach(measureFieldHash -> {
                        customQueryParamContext.getMeasures().add(
                                Optional.ofNullable(customQueryParamContext.getDataModelConfigMap().get(measureFieldHash))
                                .map(this::createMeasure)
                                .orElseThrow(() -> new ServiceException("度量不存在 fieldHash：" + measureFieldHash))
                        );
                    });
                });

        // convert measures to Map, key:fieldHash
        Map<String, QueryParam.Measure> measureMap = customQueryParamContext.getMeasures().stream()
                .collect(Collectors.toMap(QueryParam.Measure::getFieldHash, Function.identity()));
        customQueryParamContext.getMeasureMap().putAll(measureMap);
    }

    /**
     * 创建 QueryParam.Measure
     * @param config
     * @return org..colafries.common.model.metadata.QueryParam.Measure
     * @author colafries
     * @Date 2024/5/16
     */
    private QueryParam.Measure createMeasure(DataModelConfig config) {
        return QueryParam.Measure.builder()
                .field(config.getField())
                .fieldHash(config.getFieldHash())
                .defaultAggregator(config.getDefaultAggregator())
                .expression(config.getExpression())
                .calculatedFlag(config.getCalculatedFlag())
                .build();
    }

    /**
     * FilterPart:
     *
     * @param queryParam
     * @param customQuerySqlQueryContext
     * @return void
     * @author colafries
     * @Date 2024/5/16
     */
    @Override
    public void buildQuery(QueryParam queryParam, CustomQuerySqlBuildContext customQuerySqlQueryContext) {
        // measures
        List<QueryParam.Measure> measures = Optional.of(queryParam).map(QueryParam::getMeasures)
                .orElse(Collections.emptyList());
        // 处理measures
        measures.forEach(measure -> {
            ColumnRspVO customTableSchema = customQuerySqlQueryContext.getCustomTableSchemaMap().get(measure.getFieldHash());
            measure.setTableHash(customTableSchema == null ? Strings.EMPTY : customTableSchema.getTableHash());
            String field = customTableSchema == null ? Strings.EMPTY : customTableSchema.getField();
            ColumnTypeEnum columnType = ColumnTypeEnum.MEASURE;
            // defaultAggregator
            measure.setDefaultAggregator(measure.getDefaultAggregator());
            // expression
            measure.setExpression(SqlSegmentBuilderUtil.buildMeasureExpression(measure, customQuerySqlQueryContext.getFildExpMap()));
            // set select column
            customQuerySqlQueryContext.getSelectColumns().add(String.format("%s AS %s", measure.getExpression(), measure.getFieldHash()));
            // set ColumnExpMap
            customQuerySqlQueryContext.getColumnExpressionMap().put(measure.getFieldHash(), measure.getExpression());
            // set result column
            customQuerySqlQueryContext.getResultColumns().add(QueryParam.ResultColumn.builder()
                    .field(field)
                    .fieldHash(measure.getFieldHash())
                    .columnType(columnType)
                    .tableHash(measure.getTableHash())
                    .defaultAggregator(measure.getDefaultAggregator())
                    .build());
        });
    }

}
